package com.tianji.learning.utils;

import cn.hutool.core.util.StrUtil;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.JsonUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.DelayQueue;
@Slf4j
@Component
@RequiredArgsConstructor
public class LearningRecordDelayTaskHandler {

    private final StringRedisTemplate redisTemplate;
    private final LearningRecordMapper recordMapper;
    private final ILearningLessonService lessonService;
    private final  String KEY_TEMPLATE = "learning:record:{}";
    private static volatile boolean begin = true;
    private DelayQueue<DelayTask<DelayTaskData>> delayQueue = new DelayQueue<>();


    @PostConstruct
    public void init(){
        CompletableFuture.runAsync(this::handleDelayTask);
    }
    @PreDestroy
    public void destroy(){
        begin = false;
        log.debug("延迟任务停止执行！");
    }

    public void handleDelayTask(){
        while (begin) {
            try {
                // 1.获取到期的延迟任务
                DelayTask<DelayTaskData> delayTask = delayQueue.take();
                DelayTaskData data = delayTask.getData();
                // 2.查询Redis缓存
                LearningRecord record = readLearningRecordFromCache(data.getLessonId(), data.getSectionId());
                if (record == null) {
                    continue;
                }
                // 3.比较数据，moment值
                if(!Objects.equals(data.getMoment(), record.getMoment())) {
                    // 不一致，说明用户还在持续提交播放进度，放弃旧数据
                    continue;
                }

                // 4.一致，持久化播放进度数据到数据库
                // 4.1.更新学习记录的moment
                record.setFinished(null);
                recordMapper.updateById(record);
                // 4.2.更新课表最近学习信息
                LearningLesson lesson = new LearningLesson();
                lesson.setId(data.getLessonId());
                lesson.setLatestSectionId(data.getSectionId());
                lesson.setLatestLearnTime(LocalDateTime.now());
                lessonService.updateById(lesson);
            } catch (Exception e) {
                log.error("处理延迟任务发生异常", e);
            }
        }
    }



    /**
     * 实时更新学习记录 & 添加学习记录延时检测任务
     * @param learningRecord
     */
    public void addLearningRecordAndDelayCheckTask(LearningRecord learningRecord){
        log.info("正在添加学习记录，{}", learningRecord);
        // 1.暂存播放记录到redis
        writeLeaningRecordToCache(learningRecord);

        // 2.提交延时检测任务
        delayQueue.add(DelayTask.of(Duration.ofSeconds(20), BeanUtils.toBean(learningRecord, DelayTaskData.class)));


    }


    /**
     * 从缓存中读取学习记录
     * @param lessonId
     * @param sectionId
     * @return
     */
    public LearningRecord readLearningRecordFromCache(Long lessonId, Long sectionId){

            // 1.组装大key
            String key = StrUtil.format(KEY_TEMPLATE, lessonId);

            // 2.组装hashkey
            String hashKey = sectionId.toString();

            //3、发起查询，得到hashvalue
            String hashValue = (String) redisTemplate.opsForHash().get(key, sectionId);
            if(StrUtil.isBlank(hashValue)){
                log.warn("缓存中没有查询到学习记录，课表ID:{},小节ID:{}", lessonId,sectionId);
                return null;
            }
            //4、将hashvalue转为LeaningRecord
            LearningRecord learningRecord = JsonUtils.toBean(hashValue, LearningRecord.class);
            return learningRecord;
        }

    /**
     * 将学习记录写入缓存
     * @param dbRecord
     */
    public void writeLeaningRecordToCache(LearningRecord dbRecord) {
        log.info("正在将学习记录写入缓存，课表ID:{}，小节ID:{}", dbRecord.getLessonId(), dbRecord.getSectionId());

        //1、组装大key
        String key = StrUtil.format(KEY_TEMPLATE, dbRecord.getLessonId());

        //2、组装hashkey
        String hashKey = dbRecord.getSectionId().toString();

        //3、组装hashvalue
        String hashValue = JsonUtils.toJsonStr(BeanUtils.toBean(dbRecord, RecordCacheData.class));

        //4、写入缓存
        redisTemplate.opsForHash().put(key, hashKey, hashValue);
        redisTemplate.expire(key, Duration.ofDays(1));

    }



    public void cleanRecordCache(Long lessonId, Long sectionId){
        // 删除数据
        String key = StringUtils.format(KEY_TEMPLATE, lessonId);
        redisTemplate.opsForHash().delete(key, sectionId.toString());
    }

    @Data
    class RecordCacheData{
        private Long id;
        private Integer moment;
        private Boolean finished;

    }
    @Data
    class DelayTaskData {
        private Long lessonId;
        private Long sectionId;
        private Integer moment;

    }
}